﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Windows.Forms;

namespace SDFL.Native
{
    public abstract class NativeMethods
    {
#region Constants
        // notice: 
        //      firstly,I use INFINITE=0xFFFFFFFF, error:  Cannot implicitly convert type 'uint' to 'int'
        //      then, I use INFINITE=(int)0xFFFFFFFF, error: Constant value '4294967295' cannot be converted to a 'int' (use 'unchecked' syntax to override)
                                                     // because, 0xFFFFFFFF changed to Int, will overflow, so it must in unchecked()
        //      so, this is correct:  INFINITE = unchecked((int)0xffffffff)

        //      And then, 0xffffffff equivals to -1 in decimal when we are representing a 4 byte signed integer value.
        //      So, the smartest solutions is: INFINITE = -1; 
        public const Int32 INFINITE = -1;

        public const int MAX_PATH = 260;
        public const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
        public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
        public const int DUPLICATE_SAME_ACCESS = 0x2;
        public const int GENERIC_ALL_ACCESS = 0x10000000;


#endregion

#region struct

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public Int32 dwProcessID;
            public Int32 dwThreadID;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct SYSTEM_HANDLE_INFORMATION
        { // Information Class 16
            public int ProcessID;
            public byte ObjectTypeNumber;
            public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
            public ushort Handle;
            public int Object_Pointer;
            public UInt32 GrantedAccess;
        }

        [Flags]
        public enum ProcessAccessFlags : uint
        {
            All = 0x001F0FFF,
            Terminate = 0x00000001,
            CreateThread = 0x00000002,
            VMOperation = 0x00000008,
            VMRead = 0x00000010,
            VMWrite = 0x00000020,
            DupHandle = 0x00000040,
            SetInformation = 0x00000200,
            QueryInformation = 0x00000400,
            Synchronize = 0x00100000
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct OBJECT_BASIC_INFORMATION
        { // Information Class 0
            public int Attributes;
            public int GrantedAccess;
            public int HandleCount;
            public int PointerCount;
            public int PagedPoolUsage;
            public int NonPagedPoolUsage;
            public int Reserved1;
            public int Reserved2;
            public int Reserved3;
            public int NameInformationLength;
            public int TypeInformationLength;
            public int SecurityDescriptorLength;
            public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct OBJECT_TYPE_INFORMATION
        { // Information Class 2
            public UNICODE_STRING Name;
            public int ObjectCount;
            public int HandleCount;
            public int Reserved1;
            public int Reserved2;
            public int Reserved3;
            public int Reserved4;
            public int PeakObjectCount;
            public int PeakHandleCount;
            public int Reserved5;
            public int Reserved6;
            public int Reserved7;
            public int Reserved8;
            public int InvalidAttributes;
            public GENERIC_MAPPING GenericMapping;
            public int ValidAccess;
            public byte Unknown;
            public byte MaintainHandleDatabase;
            public int PoolType;
            public int PagedPoolUsage;
            public int NonPagedPoolUsage;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct OBJECT_NAME_INFORMATION
        { // Information Class 1
            public UNICODE_STRING Name;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct UNICODE_STRING
        {
            public ushort Length;
            public ushort MaximumLength;
            public IntPtr Buffer;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct GENERIC_MAPPING
        {
            public int GenericRead;
            public int GenericWrite;
            public int GenericExecute;
            public int GenericAll;
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct STARTUPINFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public Int32 Length;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;            
        }
        
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct SHELLEXECUTEINFO
        {
            public int cbSize;
            public uint fMask;
            public IntPtr hwnd;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string lpVerb;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string lpFile;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string lpParameters;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string lpDirectory;
            public int nShow;
            public IntPtr hInstApp;
            public IntPtr lpIDList;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string lpClass;
            public IntPtr hkeyClass;
            public uint dwHotKey;
            public IntPtr hIcon;
            public IntPtr hProcess;
        }


        

#endregion

#region Enums flags

        public enum SEE_MASK
        {
            ASYNCOK = 0x100000,
            CLASSKEY = 3,
            CLASSNAME = 1,
            CONNECTNETDRV = 0x80,
            DOENVSUBST = 0x200,
            FLAG_DDEWAIT = 0x100,
            FLAG_LOG_USAGE = 0x4000000,
            FLAG_NO_UI = 0x400,
            HMONITOR = 0x200000,
            HOTKEY = 0x20,
            ICON = 0x10,
            IDLIST = 4,
            INVOKEIDLIST = 12,
            NO_CONSOLE = 0x8000,
            NOCLOSEPROCESS = 0x40,
            NOQUERYCLASSSTORE = 0x1000000,
            NOZONECHECKS = 0x800000,
            UNICODE = 0x4000,
            WAITFORINPUTIDLE = 0x2000000
        }

        [Flags()]
        public enum KeyModifiers
        {
            None = 0,
            Alt = 1,
            Ctrl = 2,
            Shift = 4,
            WindowsKey = 8
        }

        public enum SECURITY_IMPERSONATION_LEVEL
        {
            SecurityAnonymous,
            SecurityIdentification,
            SecurityImpersonation,
            SecurityDelegation
        }

        public enum ObjectInformationClass : int
        {
            ObjectBasicInformation = 0,
            ObjectNameInformation = 1,
            ObjectTypeInformation = 2,
            ObjectAllTypesInformation = 3,
            ObjectHandleInformation = 4
        }

        public enum TOKEN_TYPE
        {
            TokenPrimary = 1,
            TokenImpersonation
        }

        public enum ACCESS_TYPE : uint
        {
            GENERIC_ALL = 0x10000000,
            GENERIC_READ = 0x80000000,
            GENERIC_WRITE = 0x40000000,
            GENERIC_EXECUTE = 0x20000000
        }

        public enum FILESHARE_TYPE
        {
            // Prevents other processes from opening a file or device if they request delete, read, or write access.
            NONE = 0,
            // Enables subsequent open operations on a file or device to request read access.
            FILE_SHARE_READ = 0x00000001,
            // Enables subsequent open operations on a file or device to request write access.
            FILE_SHARE_WRITE = 0x00000002,
            // Enables subsequent open operations on a file or device to request delete access.
            FILE_SHARE_DELETE = 0x00000004
        }

        public enum CREATION_TYPE
        {
            CREATE_NEW = 1,
            CREATE_ALWAYS = 2,
            OPEN_EXISTING = 3,
            OPEN_ALWAYS = 4,
            TRUNCATE_EXISTING
        }

        public enum FILE_ATTRIBUTE_TYPE
        {
            FILE_ATTRIBUTE_READONLY = 0x1,
            FILE_ATTRIBUTE_HIDDEN = 0x2,
            FILE_ATTRIBUTE_SYSTEM = 0x04,
            FILE_ATTRIBUTE_ARCHIVE = 0x32,
            FILE_ATTRIBUTE_NORMAL = 0x80,
            FILE_ATTRIBUTE_TEMPORARY = 0x100,
            FILE_ATTRIBUTE_OFFLINE = 0x1000,
        }

   
#endregion

#region API calls

        // kernel32.dll
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.None)]
        public static extern Int32 GetLastError();

        [DllImport("kernel32.dll",SetLastError=true,CharSet=CharSet.None)]
        public static extern Int32 WaitForSingleObject(IntPtr handle, Int32 timeOutMilliseconds); 
    
        [DllImport("kernel32.dll",SetLastError=true,CharSet=CharSet.None)]
        public static extern Int32 CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll",EntryPoint="GetProcessId", SetLastError = true, CharSet = CharSet.None)]
        public static extern Int32 GetProcessId(IntPtr hProcess);  

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.None)]
        public static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr lpSecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes,
            IntPtr hTemplateFile
            );

        [DllImport("kernel32.dll")]
        public static extern bool CreateProcess(
            string lpApplicationName, 
            string lpCommandLine, 
            IntPtr lpProcessAttributes, 
            IntPtr lpThreadAttributes, 
            bool bInheritHandles, 
            uint dwCreationFlags, 
            IntPtr lpEnvironment,
            string lpCurrentDirectory, 
            ref STARTUPINFO lpStartupInfo, 
            out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.None)]
        public static extern bool CreateProcessWithLogonW(
            string lpUsername,
            string lpdomain,
            string lpPassword,
            Int32 dwLogonFlags,
            string lpApplicationName,
            string lpCommandLine,
            Int32 dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            STARTUPINFO lpStartupInfo,
            PROCESS_INFORMATION lpProcessInfo
            );

        [DllImport("advapi32.dll",EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern bool CreateProcessAsUser(
            IntPtr hToken, 
            string lpApplicationName, 
            string lpCommandLine,
            ref SECURITY_ATTRIBUTES lpProcessAttributes,
            ref SECURITY_ATTRIBUTES lpThreadAttributes,                               
            bool bInheritHandle,
            Int32 dwCreationFlags, 
            IntPtr lpEnvrionment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            ref PROCESS_INFORMATION lpProcessInformation);

        
        [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx", SetLastError=true)]
        public static extern bool DuplicateTokenEx(
            IntPtr hExistingToken, 
            Int32 dwDesiredAccess,
            ref SECURITY_ATTRIBUTES lpThreadAttributes,
            Int32 ImpersonationLevel,
            Int32 dwTokenType, 
            ref IntPtr phNewToken);


        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.None)]
        public static extern Int32 LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, Int32 dwLogonType, Int32 dwLogonProvider, IntPtr phToken);

        [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.None)]
        public static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo);

        [DllImport("ntdll.dll")]
        public static extern uint NtQuerySystemInformation(int
            SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength,
            ref int returnLength);

        [DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory")]
        public static extern void CopyMemory(byte[] Destination, IntPtr Source, uint Length);

        /// <summary>
        /// Duplicate Handle, the 2nd parameter is ushort
        /// </summary>
        /// <param name="hSourceProcessHandle">source process</param>
        /// <param name="hSourceHandle">source handle</param>
        /// <param name="hTargetProcessHandle">target process</param>
        /// <param name="lpTargetHandle">target handle, A pointer to a variable that receives the duplicate handle. If lpTargetHandle is NULL, the function duplicates the handle, but does not return the duplicate handle value to the caller. This behavior exists only for backward compatibility with previous versions of this function. You should not use this feature, as you will lose system resources until the target process terminates.</param>
        /// <param name="dwDesiredAccess">The access requested for the new handle, This parameter is ignored if the dwOptions parameter specifies the DUPLICATE_SAME_ACCESS flag.</param>
        /// <param name="bInheritHandle">A variable that indicates whether the handle is inheritable. If TRUE, the duplicate handle can be inherited by new processes created by the target process. If FALSE, the new handle cannot be inherited</param>
        /// <param name="dwOptions">Optional actions. This parameter can be zero, or any combination of the following values (DUPLICATE_SAME_ACCESS 0x00000002 | DUPLICATE_CLOSE_SOURCE 0x00000001)</param>
        /// <returns></returns>
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DuplicateHandle(
            IntPtr hSourceProcessHandle,
            ushort hSourceHandle, 
            IntPtr hTargetProcessHandle,
            out IntPtr lpTargetHandle,
            uint dwDesiredAccess, 
            [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, 
            uint dwOptions
            );

        /// <summary>
        /// Duplicate handle, the 2nd parameter is IntPtr
        /// </summary>
        /// <param name="hSourceProcessHandle">source process</param>
        /// <param name="hSourceHandle">source handle</param>
        /// <param name="hTargetProcessHandle">target process</param>
        /// <param name="lpTargetHandle">target handle, A pointer to a variable that receives the duplicate handle. If lpTargetHandle is NULL, the function duplicates the handle, but does not return the duplicate handle value to the caller. This behavior exists only for backward compatibility with previous versions of this function. You should not use this feature, as you will lose system resources until the target process terminates.</param>
        /// <param name="dwDesiredAccess">The access requested for the new handle, This parameter is ignored if the dwOptions parameter specifies the DUPLICATE_SAME_ACCESS flag.</param>
        /// <param name="bInheritHandle">A variable that indicates whether the handle is inheritable. If TRUE, the duplicate handle can be inherited by new processes created by the target process. If FALSE, the new handle cannot be inherited</param>
        /// <param name="dwOptions">Optional actions. This parameter can be zero, or any combination of the following values (DUPLICATE_SAME_ACCESS 0x00000002 | DUPLICATE_CLOSE_SOURCE 0x00000001)</param>
        /// <returns></returns>
        [DllImport("kernel32.dll", SetLastError = true, EntryPoint="DuplicateHandle")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DuplicateIpHandle(
            IntPtr hSourceProcessHandle,
            IntPtr hSourceHandle,
            IntPtr hTargetProcessHandle,
            out IntPtr lpTargetHandle,
            uint dwDesiredAccess,
            [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
            uint dwOptions 
            );

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentProcess();

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);

        [DllImport("ntdll.dll")]
        public static extern int NtQueryObject(IntPtr ObjectHandle, int
            ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength,
            ref int returnLength);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);

        //如果函数执行成功，返回值不为0。
        //如果函数执行失败，返回值为0。要得到扩展错误信息，调用GetLastError。
        [DllImport("user32.dll", SetLastError = true)]
        public static extern Boolean RegisterHotKey(
            IntPtr hWnd,                //要定义热键的窗口的句柄
            int id,                     //定义热键ID（不能与其它ID重复）           
            KeyModifiers fsModifiers,   //标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效
            Keys vk                     //定义热键的内容
            );

        [DllImport("user32.dll", SetLastError = true)]
        public static extern Boolean UnregisterHotKey(
            IntPtr hWnd,                //要取消热键的窗口的句柄
            int id                      //要取消热键的ID
            );

#endregion

    }
}
